import type { CanStringified } from "../string";
import type {
  And,
  And3,
  CheckLeftIsExtendsRight,
  Or,
  IsEqual,
  Not,
} from "../common";
import type {
  IntAddSingle,
  IsEqual as IsEqualNumber,
  Compare,
} from "../number";

type GetTupleHelper<
  Length extends number = 0,
  R extends unknown[] = []
> = R["length"] extends Length ? R : GetTupleHelper<Length, [...R, unknown]>;

/**
 * #### 构造长度一定（length）的元组
 * @category Array
 * @example
 * ```ts
 * type A = GetTuple<3>; // [unknown, unknown, unknown]
 * type B = GetTuple<0>; // []
 * type C = GetTuple<1>; // [unknown]
 * ```
 */
export type GetTuple<Length extends number = 0> = GetTupleHelper<Length>;

type SetHelper<
  T extends unknown[],
  Index extends number,
  Value,
  Offset extends number = 0,
  Cache extends unknown[] = []
> = Offset extends T["length"]
  ? Cache
  : SetHelper<
      T,
      Index,
      Value,
      IntAddSingle<Offset, 1>,
      Push<Cache, Offset extends Index ? Value : T[Offset]>
    >;

/**
 * #### 修改元组中指定位置的元素
 * @category Array
 * @example
 * ```ts
 * type A = SetHelper<[1, 2, 3], 1, 0>; // [1, 0, 3]
 * ```
 */
export type ArraySet<
  T extends unknown[],
  Index extends number,
  Value
> = SetHelper<T, Index, Value>;

/**
 * #### 将元组转换为联合类型
 * @category Array
 * @example
 * ```ts
 * type A = TupleToUnion<[1,2,3]>; // 1 | 2 | 3
 * ```
 */
export type TupleToUnion<T extends unknown[]> = T[number];

/**
 * #### 去除元组的最后一位
 * @category Array
 * @example
 * ```ts
 * type A = Pop<[1, 2, 3]>; // [1, 2]
 * ```
 */
export type Pop<T extends unknown[]> = T extends [...infer F, infer _L]
  ? F
  : never;

/**
 * #### 去除元组的第一个元素
 * @category Array
 * @example
 * ```ts
 * type A = Shift<[1, 2, 3]>; // [2, 3]
 * ```
 */
export type Shift<T extends unknown[]> = T extends [infer _F, ...infer L]
  ? L
  : never;

/**
 * #### 在元组的开头添加元素
 * @category Array
 * @example
 * ```ts
 * type A = Unshift<[1, 2, 3], 0>; // [0, 1, 2, 3]
 * ```
 */
export type UnShift<T extends unknown[], Item> = [Item, ...T];

/**
 * #### 在元组的末尾添加元素
 * @category Array
 * @example
 * ```ts
 * type A = Push<[1, 2, 3], 4>; // [1, 2, 3, 4]
 * ```
 */
export type Push<T extends unknown[], Item> = [...T, Item];

/**
 * #### 将两个元组合并
 * @category Array
 * @example
 * ```ts
 * type A = Concat<[1, 2, 3], [4, 5, 6]>; // [1, 2, 3, 4, 5, 6]
 * ```
 */
export type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];

/**
 * #### 将元组用字符串连接成字符串类型
 * @category Array
 * @example
 * ```ts
 * type A = Join<["a", "b", "c"]>; // "abc"
 * type B = Join<["a", "b", "c"], "-">; // "a-b-c"
 * ```
 */
export type Join<
  T extends CanStringified[],
  SplitStr extends CanStringified = ""
> = T["length"] extends 0
  ? ""
  : T extends [infer Left, ...infer RightRest]
  ? Left extends CanStringified
    ? RightRest extends CanStringified[]
      ? `${Left}${T["length"] extends 1 ? "" : SplitStr}${Join<
          RightRest,
          SplitStr
        >}`
      : never
    : never
  : never;

type EveryHelper<
  T extends unknown[],
  Check,
  Offset extends number = 0,
  CacheBool extends boolean = true
> = T["length"] extends Offset
  ? CacheBool
  : EveryHelper<
      T,
      Check,
      IntAddSingle<Offset, 1>,
      And<CheckLeftIsExtendsRight<T[Offset], Check>, CacheBool>
    >;

/**
 * #### 检查数组中的每一个元素是否都符合条件
 * @category String
 * @example
 * ```ts
 * type A = Every<[1, 2, 3], number>; // true
 * type B = Every<[1, 2, "3"], number>; // false
 * ```
 */
export type Every<T extends unknown[], Check> = T["length"] extends 0
  ? false
  : EveryHelper<T, Check>;

type SomeHelper<
  T extends unknown[],
  Check,
  Offset extends number = 0,
  CacheBool extends boolean = false
> = T["length"] extends Offset
  ? CacheBool
  : SomeHelper<
      T,
      Check,
      IntAddSingle<Offset, 1>,
      Or<CheckLeftIsExtendsRight<T[Offset], Check>, CacheBool>
    >;

/**
 * #### 检查数组中是否有一个元素符合条件
 * @category String
 * @example
 * ```ts
 * type A = Some<[1, 2, 3], number>; // true
 * type B = Some<[1, 2, "3"], number>; // true
 * ```
 */
export type Some<T extends unknown[], Check> = SomeHelper<T, Check>;

type FillHelper<
  T extends unknown[],
  F,
  Offset extends number = 0
> = T["length"] extends 0
  ? F[]
  : Offset extends T["length"]
  ? IsEqual<T, F[]> extends true /** any[] -> T[] */
    ? T
    : F[]
  : FillHelper<Push<Shift<T>, F>, F, IntAddSingle<Offset, 1>>;

/**
 * #### 将元组中的所有元素填充为指定类型
 * @category Array
 *  @example
 * ```ts
 * type A = Fill<[1, 2, 3], 0>; // [0, 0, 0]
 * ```
 */
export type Fill<T extends unknown[], F = undefined> = FillHelper<T, F>;

type FilterHelper<
  T extends unknown[],
  C,
  Strict extends boolean,
  Offset extends number = 0,
  Cache extends unknown[] = []
> = Offset extends T["length"]
  ? Cache
  : FilterHelper<
      T,
      C,
      Strict,
      IntAddSingle<Offset, 1>,
      And<Strict, IsEqual<T[Offset], C>> extends true
        ? Push<Cache, T[Offset]>
        : And<Not<Strict>, CheckLeftIsExtendsRight<T[Offset], C>> extends true
        ? Push<Cache, T[Offset]>
        : Cache
    >;

/**
 * #### 过滤出元组类型中符合条件的类型
 * ##### 严格模式，即 any 只能为 any，而不能为 1、unknown 这样的其他类型
 * @category Array
 * @example
 * ```ts
 * type A = Filter<["1", "2", 3, any, 1], 1>; // ["1", 1]
 * ```
 */
export type Filter<
  T extends unknown[],
  C,
  Strict extends boolean = false
> = FilterHelper<T, C, Strict>;

type FindHelper<
  T extends unknown[],
  C,
  Offset extends number = 0
> = Offset extends IntAddSingle<T["length"], 1>
  ? null
  : CheckLeftIsExtendsRight<T[Offset], C> extends true
  ? T[Offset]
  : FindHelper<T, C, IntAddSingle<Offset, 1>>;

/**
 * #### 获取元组中第一个符合条件的元素
 * @category Array
 * @example
 * ```ts
 * type A = Find<[1, 2, 3, 1], 1>; // 1
 * ```
 */
export type Find<T extends unknown[], C> = FindHelper<T, C>;

// type a = Find<[1, 2, 3, 1], 4>;

/**
 * #### 获取元组中最后一个符合条件的元素
 * @category Array
 * @example
 * ```ts
 * type A = FindLast<[1, 2, 3, 1], 1>; // 1
 * ```
 */
export type FindLast<T extends unknown[], C> = Find<Reverse<T>, C>;

interface IndexMappedItem<Item, Index extends number, Tuple extends unknown[]> {
  item: Item;
  index: Index;
  tuple: Tuple;
}

type MapWidthIndexHelper<
  T extends unknown[],
  Offset extends number = 0,
  Cache extends unknown[] = []
> = T["length"] extends Offset
  ? Cache
  : MapWidthIndexHelper<
      T,
      IntAddSingle<Offset, 1>,
      Push<Cache, IndexMappedItem<T[Offset], Offset, T>>
    >;

/**
 * #### 获取元组中每个元素的索引
 * @category Array
 * @example
 * ```ts
 * type Result=MapWidthIndex<[1, 2]>; // [{item:1;index:0;tuple:[1, 2]},{item:2;index:1;tuple:[1, 2]}]
 * ```
 */
export type MapWidthIndex<T extends unknown[]> = MapWidthIndexHelper<T>;

type FindIndexHelper<
  T extends unknown[],
  C,
  Strict extends boolean = false,
  Offset extends number = 0
> = Offset extends IntAddSingle<T["length"], 1>
  ? -1
  : And<IsEqual<T[Offset], C>, Strict> extends true
  ? Offset
  : And<CheckLeftIsExtendsRight<T[Offset], C>, Not<Strict>> extends true
  ? Offset
  : FindIndexHelper<T, C, Strict, IntAddSingle<Offset, 1>>;

/**
 * #### 获取元组中第一个符合条件的元素的索引
 * @category Array
 * @example
 * ```ts
 * type A = FindIndex<[1, 2, 3, 1], 1>; // 0
 * ```
 */
export type FindIndex<
  T extends unknown[],
  C,
  Strict extends boolean = false
> = FindIndexHelper<T, C, Strict>;

type FindLastIndexHelper<
  T extends unknown[],
  C,
  Item = Find<Reverse<MapWidthIndex<T>>, IndexMappedItem<C, number, T>>
> = Item extends IndexMappedItem<C, number, T> ? Item["index"] : -1;

/**
 * #### 获取元组中最后一个符合条件的元素的索引
 * @category Array
 * @example
 * ```ts
 * type A = FindLastIndex<[1, 2, 3, 1], 1>; // 3
 * ```
 */
export type FindLastIndex<T extends unknown[], C> = FindLastIndexHelper<T, C>;

type ReverseHelper<
  T extends unknown[],
  Offset extends number = 0,
  Cache extends unknown[] = []
> = Cache["length"] extends T["length"]
  ? Cache
  : ReverseHelper<T, IntAddSingle<Offset, 1>, UnShift<Cache, T[Offset]>>;

/**
 * #### 反转数组
 * @category Array
 * @example
 * ```ts
 * type A = Reverse<[1, 2, 3]>; // [3, 2, 1]
 * ```
 */
export type Reverse<T extends unknown[]> = ReverseHelper<T>;
export type RevArr<T extends unknown[]> = T extends [infer F, ...infer Rest]
  ? [...RevArr<Rest>, F]
  : T;

/**
 * #### 判断数组中是否包含某个元素
 * @category Array
 * @example
 * ```ts
 * type A = Includes<[1, 2, 3], 1>; // true
 * ```
 */
export type Includes<T extends unknown[], C> = CheckLeftIsExtendsRight<
  C,
  TupleToUnion<T>
>;

type SliceHelper<
  T extends unknown[],
  Start extends number,
  End extends number,
  Offset extends number = 0,
  Cache extends unknown[] = []
> = IsEqualNumber<Offset, End> extends true
  ? Cache
  : SliceHelper<
      T,
      Start,
      End,
      IntAddSingle<Offset, 1>,
      And3<
        Or<Compare<Offset, Start>, IsEqualNumber<Offset, Start>>,
        Or<Compare<End, Offset>, IsEqualNumber<Offset, End>>,
        Or<Compare<T["length"], Offset>, IsEqualNumber<T["length"], End>>
      > extends true
        ? Push<Cache, T[Offset]>
        : Cache
    >;

/**
 * #### 截取数组
 * @category Array
 * @example
 * ```ts
 * type A = Slice<[1, 2, 3], 0, 2>; // [1, 2]
 * ```
 */
export type Slice<
  T extends unknown[],
  Start extends number,
  End extends number
> = SliceHelper<T, Start, End>;

type SortHepler1<
  T extends number[],
  Offset extends number = 0
> = Offset extends T["length"] ? T : SortHepler2<T, Offset>;

type SortHepler2<
  T extends number[],
  Offset extends number = 0,
  Offset1 extends number = 0,
  Offset1Added extends number = IntAddSingle<Offset1, 1>,
  Seted1 extends unknown[] = ArraySet<T, Offset1Added, T[Offset1]>,
  Seted2 extends unknown[] = ArraySet<Seted1, Offset1, T[Offset1Added]>
> = IntAddSingle<IntAddSingle<Offset, Offset1>, 1> extends T["length"]
  ? SortHepler1<T, IntAddSingle<Offset, 1>>
  : SortHepler2<
      Compare<T[Offset1], T[Offset1Added]> extends true
        ? Seted2 extends number[]
          ? Seted2
          : never
        : T,
      IntAddSingle<Offset1, 1>
    >;

export type Sort<T extends number[]> = SortHepler1<T>;

// type test = GetTuple<3>;
// type test2 = Every<[1, 2, 3], number>;
// type some = Some<[1, 2, "3"], number>;
// type fill = Fill<[1, 2, 3, any], 1>;
// type filter = Filter<["1", "2", 3, any, 1], 1>;
// type find = Find<[1, 2, 3, any, 1], 1>;

// type findIndex = FindLastIndex<[1, 2, 3, any, 1], 1>;

// type reverse = Reverse<[1, 2, 3, any, 1]>;
// type slice = Slice<[1, 2, 3, any, 1], 0, 3>;
// type sort = Sort<[3, 2]>;
